﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Xml.Serialization;

namespace ChineseChess.Game.AI
{


    public class Ai: BaseAi
    { 
        /// <summary>
        /// Ai的算法
        /// </summary>
        /// <param name="pieceList">当前局面</param>
        /// <param name="canvas"></param>
        /// <param name="deep">计算深度</param>
        public static void Run(List<Piece> pieceList,Canvas canvas,int deep = 6)
        {
            //List<Score> scores = new List<Score>(); //存放局面估分
            //List<Piece> pies = CopyList(pieceList);
            //for (int i = 0; i < pies.Count; i++)
            //{   //遍历走子
            //    var pie = pies[i];

            //    if (pie.isRed == false) //当前走的子,第一步， 黑子走
            //    {
            //        List<Point> point = pie.rule.getNextPos(pie,pieceList); //该子下一步可走的点

            //        for (int j = 0; j < point.Count; j++)
            //        {
            //            var sc = RunNextStep(pies, pie, i, point[j], false); //走子
            //            var t = Search(0, deep, pieceList, pie, point[j], 0, false, pie, point[j], pieceList);// //下一深度的走子信息搜索 
            //            scores.Add(t);
            //        }
            //    }
            //}


            //int maxscore = int.MinValue;
            //Score maxScore = null;
            //for (int i = 0; i < scores.Count; i++) 
            //{
            //    if(maxscore<scores[i].score)
            //    {   //获取最高分
            //        maxscore = scores[i].score;
            //        maxScore = scores[i];
            //    }
            //}

            //Piece p = clearPiece(pieceList, maxScore.x, maxScore.y);//吃掉子
            //if (p != null)
            //{
            //    canvas.Children.Remove(p);
            //}

            //pieceList[maxScore.i].X = maxScore.x;
            //pieceList[maxScore.i].Y = maxScore.y;
            //pieceList[maxScore.i].InvalidateVisual();


            Moves mv = searchMain(pieceList);
            Piece p = clearPiece(pieceList, (int)mv.p.X, (int)mv.p.Y);//吃掉子
            MessageBox.Show(mv.pie.Name.ToString() + mv.pie.X +"," + mv.pie.Y + ", "+ mv.p.ToString());
            if (p != null)
            {
                canvas.Children.Remove(p);
            }

            for(int i = 0; i< pieceList.Count;i++)
            {
                var pie = pieceList[i];
                if(pie.X == mv.pie.X && pie.Y == mv.pie.Y)
                {
                    pie.X = (int)mv.p.X;
                    pie.Y = (int)mv.p.Y;
                    pie.InvalidateVisual();
                }  
            } 
        }

        public static Moves searchMain(List<Piece> pieceList)
        {
            maxMinSearch(pieceList);
            return mvResult;
        }

        static int MINMAXDEPTH = 2;
        static private Pos pos = new Pos();
        //极大极小搜索
        public static void maxMinSearch(List<Piece> pieceList)
        {
            pos.PieceList = CopyList(pieceList);
            if(pos.CurrectCamp == true)
            {
                maxSearch(MINMAXDEPTH);
            }
            else
            {
                minSearch(MINMAXDEPTH);
            }
        }

        static Moves mvResult;
        private static int maxSearch(int depth)
        {
            if(depth == 0)
            {
                return pos.evaluate();
            }
            var vlBest = int.MinValue;
            var mvs = pos.generateMoves();
            Moves mv;
            int value = 0;

            for (int i = 0; i < mvs.Count; i++)
            {
                mv = mvs[i];
                if(! pos.makeMove(mv))
                {   // 这招棋走完后，老将处于被攻击的状态
                    continue;
                }

                // 调用极小点搜索算法，搜索深度为depth - 1
                value = minSearch(depth - 1);
                // 撤销mv走法
                pos.undoMakeMove(mv);
                // 寻找最大估值
                if (value > vlBest)
                {
                    // 找到了当前的最佳值	  
                    vlBest = value;

                    // 如果回到了根节点，需要记录根节点的最佳走法
                    if (depth == MINMAXDEPTH)
                    {
                        mvResult = mv;
                    }
                }
            }
            return vlBest;	// 返回当前节点的最优值
        }

        private static int minSearch(int depth)
        {
            if (depth == 0)
            {
                return pos.evaluate();
            }

            var vlBest = int.MaxValue;                // 初始最优值为正无穷，这里与极大点搜索不同
            var mvs = pos.generateMoves();
            Moves mv;
            var value = 0;
            for (var i = 0; i < mvs.Count; i++)
            {
                mv = mvs[i];
                if (!pos.makeMove(mv))
                {
                    continue;
                }
                value = maxSearch(depth - 1);  // 这里与极大点搜索不同
                pos.undoMakeMove(mv);

                if (value < vlBest)
                {               // 这里与极大点搜索不同
                    vlBest = value;
                    if (depth == MINMAXDEPTH)
                    {
                        mvResult = mv;
                    }
                }
            }
            return vlBest;	// 返回当前节点的最优值 
        } 


        /// <summary>
        /// 搜索算法
        /// </summary>
        /// <param name="depth">当前深度</param>
        /// <param name="nDepth">要搜索的深度</param>
        /// <param name="pieceList">当前棋盘</param>
        /// <param name="npie">当前走的子</param>
        /// <param name="p">当前走的点</param>
        /// <param name="ii">走的是哪个子</param>
        /// <param name="isRed">走子方</param>
        /// <param name="firstPie">第一步走的子</param>
        /// <param name="firstPoint">第一步的子走的位置</param>
        /// <param name="firstPieceList">第一步时候的棋盘局面</param>
        /// <returns></returns>
        public static Score Search(int depth,int nDepth, List<Piece> pieceList,Piece npie,Point p,int ii,bool isRed, Piece firstPie,Point firstPoint, List<Piece> firstPieceList)
        {
            if(depth == nDepth)
            {
                //获取当前深度的得分信息及走子信息
                int sc = getScore(pieceList, isRed);
                return new Score(sc, firstPie, ii, (int)firstPoint.X, (int)firstPoint.Y);
            }

            List<Piece> firstPieces = firstPieceList;
            List<Piece> pies = CopyList(pieceList);
             
            for (int i = 0; i < pies.Count; i++)
            {   //遍历走子
                var pie = pies[i];

                if (pie.isRed == isRed) //当前走的子
                { 
                    List<Point> point = pie.rule.getNextPos(pie, pies); //该子下一步可走的点

                    for (int j = 0; j < point.Count; j++) 
                    {
                        var sc = RunNextStep(pies, pie, i, point[j], isRed); //走子
                        var t = Search(depth + 1, nDepth, pies, pie, point[j], i, isRed, firstPie, firstPoint, firstPieces); //下一深度的走子信息搜索
                        return t;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 模拟走下一步的子,返回当前走子后的得分信息
        /// </summary>
        /// <param name="pieceList">当前棋盘</param>
        /// <param name="pie"></param>
        /// <param name="p"></param>
        /// <param name="isred"></param>
        public static Score RunNextStep(List<Piece> pieceList, Piece pie, int i, Point p, bool isred)
        { 
            List<Piece> pies = (pieceList); //复制棋局
            
            int historyX = pie.X;
            int historyY = pie.Y;
            int x = (int)pie.X;
            int y = (int)pie.Y;
            Piece eatedPie = clearPiece(pies, x, y, !isred); //被吃掉的子
            pie.setXy(x, y); //把该子走到该点
            int sc = getScore(pies, isred);
            //if (eatedPie != null)
            //{
            //    pies.Add(eatedPie); // 还原被吃掉的子
            //}
            //pie.setXy(historyX, historyY);
            return new Score(sc, pie, i, (int)p.X, (int)p.Y);
        }

    }
}
